package com.evil.application.pojo.dto.reporting;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.script.JavaScriptEngine;
import com.alibaba.fastjson.annotation.JSONField;
import com.evil.application.enums.reporting.ReportingDateUnitEnum;
import com.evil.application.enums.reporting.ReportingTargetTypeEnum;
import com.evil.application.pojo.dto.form.control.code.ControlDTO;
import com.evil.application.pojo.dto.form.control.code.TableControlDTO;
import com.evil.common.application.dto.order.OrderPageDataRespDTO;
import com.evil.common.application.enums.CurrencyCodeEnum;
import com.evil.common.application.enums.FormatTypeEnum;
import com.evil.common.application.enums.SortTypeEnum;
import com.evil.application.enums.reporting.SummaryTypeEnum;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.NumberUtils;
import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.lang3.StringUtils;

import javax.validation.constraints.NotNull;
import java.math.RoundingMode;
import java.util.Objects;
import java.util.Optional;

/**
 * 报表指标
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Data
@Accessors(chain = true)
public class ReportingTargetDTO extends AggBaseDTO {

    /**
     * 指标类型{@link ReportingTargetTypeEnum}
     */
    @NotNull(message = "指标类型不能为空")
    private Integer targetType;

    /**
     * 控件code（控件id，targetType=0时有值）
     */
    private String controlCode;

    /**
     * 属于表格子控件
     */
    private Boolean beingTableControl;

    /**
     * 公式（targetType=1时有值）{@link JavaScriptEngine}
     */
    private String formula;

    /**
     * 时间单位（targetType=2|3时有值）{@link ReportingDateUnitEnum}
     */
    private Integer dateUnit;

    /**
     * 汇总方式（targetType!=1时有值）（该指标的汇总方式）{@link SummaryTypeEnum}
     */
    private Integer summaryType;

    /**
     * 列汇总方式（在表格最后一行“列汇总”中，对该指标对应所有数据进行汇总的方式）{@link SummaryTypeEnum}
     */
    private Integer columnSummaryType;

    /**
     * 小计方式（该指标每行数据的汇总方式）{@link SummaryTypeEnum}
     */
    private Integer totalType;

    /**
     * 排序方式（其他指标的排序方式设置将失效）{@link SortTypeEnum}
     */
    private Integer sortType;

    /**
     * 显示格式 {@link FormatTypeEnum}
     */
    private Integer formatType;

    /**
     * 金额单位 {@link CurrencyCodeEnum}
     */
    private String currencyCode;

    /**
     * 小数位数（填写者可输入限制小数位数，否则默认为不限制）
     */
    private Integer decimal;

    /**
     * 后端专用
     */
    @JSONField(serialize = false)
    private String key;

    public ReportingTargetDTO() {
        this.targetType = ReportingTargetTypeEnum.CONTROL.getId();
        this.setControlId(0L);
        this.beingTableControl = false;
        this.dateUnit = ReportingDateUnitEnum.MINUTE.getId();
        this.summaryType = SummaryTypeEnum.SUM.getId();
        this.columnSummaryType = SummaryTypeEnum.SUM.getId();
        this.totalType = SummaryTypeEnum.SUM.getId();
        this.sortType = SortTypeEnum.DEFAULT.getId();
        this.formatType = FormatTypeEnum.DEFAULT.getId();
        this.key = UUID.fastUUID().toString(true);
    }

    public ReportingTargetDTO(ReportingTargetDTO reportingTarget) {
        this.setTitle(reportingTarget.getTitle());
        this.targetType = reportingTarget.targetType;
        this.setControlId(reportingTarget.getControlId());
        this.controlCode = reportingTarget.controlCode;
        this.beingTableControl = reportingTarget.beingTableControl;
        this.formula = reportingTarget.formula;
        this.dateUnit = reportingTarget.dateUnit;
        this.summaryType = reportingTarget.summaryType;
        this.columnSummaryType = reportingTarget.columnSummaryType;
        this.totalType = reportingTarget.totalType;
        this.sortType = reportingTarget.sortType;
        this.formatType = reportingTarget.formatType;
        this.currencyCode = reportingTarget.currencyCode;
        this.decimal = reportingTarget.decimal;
        this.key = UUID.fastUUID().toString(true);
    }

    public ReportingTargetDTO(String key, Long controlId, String title, Integer summaryType) {
        this.targetType = ReportingTargetTypeEnum.CONTROL.getId();
        this.setControlId(controlId);
        this.setTitle(title);
        this.beingTableControl = false;
        this.dateUnit = ReportingDateUnitEnum.MINUTE.getId();
        this.summaryType = summaryType;
        this.columnSummaryType = SummaryTypeEnum.SUM.getId();
        this.totalType = SummaryTypeEnum.SUM.getId();
        this.sortType = SortTypeEnum.DEFAULT.getId();
        this.formatType = FormatTypeEnum.DEFAULT.getId();
        this.key = key;
    }

    public ReportingTargetDTO(ControlDTO controlDTO, SummaryTypeEnum summaryTypeEnum) {
        this.targetType = ReportingTargetTypeEnum.CONTROL.getId();
        this.setControlId(controlDTO.getControlId());
        this.setTitle(controlDTO.getControlTitle());
        this.beingTableControl = controlDTO instanceof TableControlDTO;
        this.dateUnit = ReportingDateUnitEnum.MINUTE.getId();
        this.summaryType = summaryTypeEnum.getId();
        this.columnSummaryType = SummaryTypeEnum.SUM.getId();
        this.totalType = SummaryTypeEnum.SUM.getId();
        this.sortType = SortTypeEnum.DEFAULT.getId();
        this.formatType = FormatTypeEnum.DEFAULT.getId();
        this.key = controlDTO.getControlField();
    }

    public ReportingTargetDTO copy() {
        return BeanUtil.copyProperties(this, ReportingTargetDTO.class);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ReportingTargetDTO that = (ReportingTargetDTO) o;
        return Objects.equals(key, that.key);
    }

    @Override
    public int hashCode() {
        return Objects.hash(key);
    }

    public String format(Object obj) {
        if (NumberUtils.isNum(obj) || obj instanceof String) {
            // 转成字符串
            String result = this.formatDecimal(obj);
            // 显示格式
            result = FormatTypeEnum.isExistById(this.formatType).getFormat().apply(Optional.of(result)).orElse(result);
            // 金额符号
            if (StringUtils.isNotBlank(this.getCurrencyCode())) {
                String symbol = CurrencyCodeEnum.isExistByCode(this.getCurrencyCode()).getCurrencyCodeSymbol();
                result = String.format("%s %s", symbol, result);
            }
            return result;
        }
        // 流程处理时长
        else if (obj instanceof OrderPageDataRespDTO) {
            return "暂不支持流程时长运算";
        }
        return Objects.toString(obj, null);
    }

    public String formatDecimal(Object value) {
        return NumberUtils.toString(value, this.decimal, RoundingMode.HALF_UP);
    }

    public String restore(String target) {
        if (StringUtils.isNotBlank(target)) {
            if (StringUtils.isNotBlank(this.getCurrencyCode())) {
                String symbol = CurrencyCodeEnum.isExistByCode(this.getCurrencyCode()).getCurrencyCodeSymbol();
                if (target.contains(symbol)) {
                    target = target.substring(target.lastIndexOf(symbol) + 2);
                }
            }
            target = FormatTypeEnum.isExistById(this.formatType).getRestore().apply(Optional.of(target)).orElse(target);
        }
        return target;
    }

    public boolean checkControl() {
        return Long.valueOf(0).equals(this.getControlId());
    }

    public void checkProps() {
        ReportingTargetTypeEnum.isExistById(this.targetType);
        if (ReportingTargetTypeEnum.CONTROL.getId() == this.targetType) {
            if (this.checkControl()) {
                throw new BusinessException(RCodeEnum.ERROR_PARAMETER, "指标id参数错误");
            }
        }
        if (Objects.nonNull(this.dateUnit)) {
            ReportingDateUnitEnum.isExistById(this.dateUnit);
        }
        if (Objects.nonNull(this.summaryType)) {
            SummaryTypeEnum.isExistById(this.summaryType);
        }
        if (Objects.nonNull(this.columnSummaryType)) {
            SummaryTypeEnum.isExistById(this.columnSummaryType);
        }
        if (Objects.nonNull(this.totalType)) {
            SummaryTypeEnum.isExistById(this.totalType);
        }
        if (Objects.nonNull(this.sortType)) {
            SortTypeEnum.isExistById(this.sortType);
        }
        if (Objects.nonNull(this.formatType)) {
            FormatTypeEnum.isExistById(this.formatType);
        }
        if (StringUtils.isNotBlank(this.currencyCode)) {
            CurrencyCodeEnum.isExistByCode(this.currencyCode);
        }
    }
}
